package cc.verywell.pureblock.msg.nfs;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import cc.verywell.pureblock.func.node.KeyShell;
import cc.verywell.pureblock.func.node.NodeBucket.ValueShell;

/**
* <pre> 
* +++++++++++++++
* +    Entry    +
* +++++++++++++++
* + Key + Value +
* +++++++++++++++
* </pre>
* <p>
* 
* 
* ok, memory low.
* 50万邻居排序7秒返回，100万邻居内存会溢出(limit500Mb);
* 如有幸发布至公链使用，请务必重载Top-K算法;
* 
* 
* </p>
* Copyright © 2019 TanYaqiu. All rights reserved.
* @author TanYaqiu 
* @address flat 601
* @date 2019年3月23日 下午4:28:36
*/
public abstract class NfsNodeBucket<T extends NfsNodeShell> {
	static public int NEW_KEYS_THROWED = 16;

//	static private NodeBucket instance = new NodeBucket();
//	static public NodeBucket getInstance() {
//		return instance;
//	}
	protected abstract T newShell(ValueShell v);
	protected abstract T[] newShellArray(int size);

	final protected Map<KeyShell,T> map;
	public NfsNodeBucket() { 
		map = new ConcurrentHashMap<>();
	}
	
	public T addValue(ValueShell v) {///对func内部使用;
		T nv = newShell(v);
		T old = map.putIfAbsent(v.key, nv);
		return old!=null?old:nv;
	}
	public void removeValue(ValueShell v) {///对func内部使用;
		T t = map.get(v.key);
		if(t!=null && t.v==v)map.remove(v.key,t);
	}
	public T getValue(KeyShell key) {
		return map.get(key);
	}
	
	/**
	 * <p>prior return connecting or had connected node</p>;
	 * Copyright © 2019 TanYaqiu. All rights reserved.
	 * @param KEY
	 * @param MAXreturn
	 * @return
	 */
	public List<T> getTargetNearby(final byte[] KEY,final int MAXreturn){
		if(MAXreturn<=0)return Collections.emptyList();//new ArrayList<>(0);
		Comparator<T> c = new Comparator<T>() {
			public int compare(T o1, T o2) {
				return o1.v.getDistance(KEY)-o2.v.getDistance(KEY);
			}
		};
		
		Collection<T> vs  = map.values();
		T[] ds = newShellArray( Math.min(vs.size(), MAXreturn*3) );
		int i=0, topk = Math.min(MAXreturn, ds.length);
		T p = null;
		for (T v : vs) {
			//if(v==myNode)continue; //自身除外;
			if(p==null || 0>c.compare(p, v)) {
				ds[i++]=v;
				if(i==ds.length) {
					Arrays.sort(ds, c);
					i = topk;
					p = ds[i-1];
				}
			}
		}
		if(i!=topk)Arrays.sort(ds,0,i,c);
		
		return Arrays.asList(ds).subList(0, Math.min(i, topk));
	}

}
